#ifndef SDLPP_DISPLAY_HPP
#define SDLPP_DISPLAY_HPP

#include <string>

// Available compile-time preprocessor options:
// SDLPP_SKIP_IMAGE
// SDLPP_SKIP_TTF
// Doing so would sacrifice features in favour for a reduced dependency tree.

// It is recommended you use the "sdl-config" flags when compiling. Of course,
// that might be a problem for Windows users not running a shell environment.
// Sucks to be you. :P

#include <SDL.h>

#ifndef SDLPP_SKIP_IMAGE
#include <SDL_image.h>
#endif

#ifndef SDLPP_SKIP_TTF
#include <SDL_ttf.h>
#endif

namespace sdl
{
// =============================================================================
// Rect

class Rect: public SDL_Rect
{
public:
    Rect(int X, int Y, int W, int H);
    Rect(int X, int Y);
    Rect();
    bool isEnclosing (Rect box);
    bool isOverlapping (Rect box);
    void trim(int amount);
};
bool operator== (Rect &r1, Rect &r2);
bool operator!= (Rect &r1, Rect &r2);

// =============================================================================
// Time

class Limiter
{
private:
    uint32_t lasttick;
public:
    Limiter();
    uint32_t interval();
    float tick(uint32_t caprate = 0);
    void reset();
    void update();
};

void delay(uint32_t utime);

// =============================================================================
// Initialisers

void init();
// Actually, uninit is really ncessary when you are using a fullscreen program
// or when you are using the fonts.
void uninit();

// =============================================================================
// Color

class Colour : public SDL_Color
{
public:
    uint8_t a;
    Colour();
    Colour(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255);
};
bool operator== (Colour &c1, Colour &c2);
bool operator!= (Colour &c1, Colour &c2);

#define Color Colour

namespace mask
{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    const uint32_t Rmask = 0xff000000;
    const uint32_t Gmask = 0x00ff0000;
    const uint32_t Bmask = 0x0000ff00;
    const uint32_t Amask = 0x000000ff;
#else
    const uint32_t Rmask = 0x000000ff;
    const uint32_t Gmask = 0x0000ff00;
    const uint32_t Bmask = 0x00ff0000;
    const uint32_t Amask = 0xff000000;
#endif
}
// =============================================================================
// Surface

class Surface
{
protected:
    void open(SDL_Surface * surf);
    long* count;
    void destroy();

public:
    SDL_Surface * mSurface;
    Surface();
    Surface(const Surface& s);

    ~Surface();

    int w();
    int h();
    Rect size();
    int depth();

    void fill(Rect box, Colour colour);

    Surface& operator= (const Surface& s);
};

// =============================================================================
// Display

class Display : public Surface
{
public:
    Display():Surface(){}
    Display(const Surface& s):Surface(s){}
    Display(const Display& s):Surface(s){}
    Display(int w, int h, int depth = 32, uint32_t flags = SDL_HWSURFACE | SDL_DOUBLEBUF);

    void create(int w, int h, int depth = 32, uint32_t flags = SDL_HWSURFACE | SDL_DOUBLEBUF);
    bool fullscreen();
    bool fullscreen(bool value);
    void update();

    static void title(std::string text);
    static void icon(Surface* image);
};

// =============================================================================
// Image

class Image : public Surface
{
public:
    Image():Surface(){}
    Image(const Surface& s):Surface(s){}
    Image(const Image& s):Surface(s){}
    Image(std::string filename);

    void open(std::string filename);
    void open(SDL_Surface * surf);
    void create(int w, int h, uint32_t depth, uint32_t flags = SDL_HWSURFACE);

    void render(Surface* target);
    void render(Rect dest, Surface* target);
    void render(Rect src, Rect dest, Surface* target);
};

#ifndef SDLPP_SKIP_TTF
// =============================================================================
// Text

// Forward declaration
class Font;

class Text
{
protected:
    Image mImage;
    std::string oText;
    Colour oColour;
    bool oAalias;
    Font * oFont;
    void redraw();

public:
    Text();
    Text(Font & fnt, Colour col, bool aa = true);
    ~Text();

    Rect size();
    bool aalias;
    Font * font;
    Colour colour;
    std::string text;

    void render(Rect dest, Surface* target);
    void render(Rect src, Rect dest, Surface* target);

    friend class Font;
};

// =============================================================================
// Font

class Font
{
protected:
    TTF_Font * mFont;
    long *count;
    void destroy();

public:
    Font();
    Font(const Font& s);
    Font(std::string filename, int size, int index = 0);
    ~Font();

    int w(std::string &s);
    int h();
    Rect size(std::string &s);
    void open(std::string filename, int size, int index = 0);

    friend class Text;

    Font& operator= (const Font& f);
};
#endif

}

#endif
